//
//  DownloadViewModel.m
//  VideoPlayer
//
//  Created by 白璐 on 16/9/19.
//  Copyright © 2016年 baidu. All rights reserved.
//

#import "DownloadViewModel.h"

#import <UIKit/UIKit.h>

#import "NetworkAlertVC.h"
#import <BDCloudMediaDownloader/BDCloudMediaDownloader.h>
#import "NetworkMonitor.h"


@interface DownloadItem : NSObject
@property(nonatomic, strong) VideoItem* info;
@property(nonatomic, strong) BDCloudMediaDownloadTask* task;
@property(nonatomic, strong) BDCloudMediaItem* item;
@property(nonatomic, assign) DownloadState state;
@property(nonatomic, assign) BOOL autoPaused;

- (instancetype)initWithVideoItem:(VideoItem*)item;
- (void)action:(BDCloudMediaDownload*)downloader;
- (void)stop:(BDCloudMediaDownload*)downloader;
- (void)remove:(BDCloudMediaDownload*)downloader;
@end

@implementation DownloadItem

- (instancetype)initWithVideoItem:(VideoItem*)item {
    if (self = [super init]) {
        _info = item;
        _state = DownloadStateNone;
    }
    return self;
}

- (void)action:(BDCloudMediaDownload*)downloader {
    switch (self.state) {
        case DownloadStateNone: {
            NSError* error;
            self.task = [downloader downloadTaskWithURL:self.info.url title:self.info.title error:&error];
            self.item = self.task.item;
            if (error) {
                if (error.code == BDCloudMediaDownloadErrorCodeAlreadyExists) {
                    self.item = [self findMediaItem:self.info.url inDownloader:downloader];
                    self.state = DownloadStateCompleted;
                }
                break;
            }
            self.state = DownloadStateRunning;
            break;
        }
        case DownloadStateRunning:
            [downloader suspendTask:self.task];
            self.state = DownloadStateSuspend;
            break;
        case DownloadStateSuspend:
            [downloader resumeTask:self.task];
            self.state = DownloadStateRunning;
            break;
        default:
            break;
    }
}

- (void)stop:(BDCloudMediaDownload*)downloader {
    [downloader cancelTask:self.task];
    self.state = DownloadStateNone;
    self.task = nil;
}

- (void)remove:(BDCloudMediaDownload*)downloader {
    if (self.task) {
        [downloader cancelTask:self.task];
    } else if (self.item) {
        [downloader removeMediaItem:self.item];
    }
}

- (BDCloudMediaItem*)findMediaItem:(NSString*)url inDownloader:(BDCloudMediaDownload*)downloader {
    NSArray<BDCloudMediaItem*>* items = [downloader mediaItems];
    for (BDCloudMediaItem* item in items) {
        if ([item.url isEqualToString:url]) {
            return item;
        }
    }
    return nil;
}

@end

@interface DownloadViewModel () <BDCloudMediaDownloadDelegate>
@property(nonatomic, strong) BDCloudMediaDownload* downloader;
@property(nonatomic, strong) NSMutableArray<DownloadItem*>* items;
@property(nonatomic, strong) NetworkMonitor* monitor;
@end

@implementation DownloadViewModel

+ (DownloadViewModel*)defaultModel {
    static DownloadViewModel* model;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        model = [[DownloadViewModel alloc] initInternal];
    });
    return model;
}

- (instancetype)initInternal {
    if (self = [super init]) {
        _downloader = [[BDCloudMediaDownload alloc] initWithUser:@"baidu" delegate:self];
        _items = [NSMutableArray array];
        
        __weak typeof(self) wself = self;
        _monitor = [[NetworkMonitor alloc] init];
        _monitor.networkChangedBlock = ^(NetworkType network) {
            [wself networkChanged:network];
        };
        
        [_monitor start];
    }
    
    return self;
}

- (void)dealloc {
    [_monitor stop];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)cancenDownloads {
    for (DownloadItem* item in self.items) {
        if (!item.autoPaused
            && item.state == DownloadStateRunning) {
            [item action:self.downloader];
            item.autoPaused = YES;
        }
    }
}

- (void)continueDownloads {
    for (DownloadItem* item in self.items) {
        if (item.autoPaused
            && item.task.state == BDCloudMediaDownloadTaskStateSuspend
            && item.state == DownloadStateSuspend) {
            [item action:self.downloader];
            item.autoPaused = NO;
        }
    }
}


- (NSUInteger)count {
    return self.items.count;
}

- (NSString*)image:(NSUInteger)index {
    return self.items[index].info.img;
}

- (NSString*)title:(NSUInteger)index {
    return self.items[index].info.title;
}

- (NSString*)detail:(NSUInteger)index {
    return self.items[index].info.detail;
}

- (NSString*)url:(NSUInteger)index {
    DownloadState state = [self state:index];
    DownloadItem* item = self.items[index];
    if (state == DownloadStateCompleted) {
        return [item.item.path stringByAppendingPathComponent:item.item.index];
    } else {
        return item.info.url;
    }
}

- (NSString*)token:(NSUInteger)index {
    return self.items[index].info.token;
}

- (DownloadState)state:(NSUInteger)index {
    return self.items[index].state;
}

- (float)progress:(NSUInteger)index {
    return self.items[index].task.progress;
}

- (BOOL)isDownloading:(NSString*)url {
    for (DownloadItem* item in self.items) {
        if ([item.info.url isEqualToString:url]) {
            return YES;
        }
    }
    
    return NO;
}

- (NSString*)cellIdentifier:(NSUInteger)index {
    DownloadState state = [self state:index];
    switch (state) {
        case DownloadStateNone:
        case DownloadStateRunning:
        case DownloadStateSuspend:
            return @"offlineCell";
        case DownloadStateCompleted:
            return @"onlineCell";
    }
}

#pragma mark - user actions

- (void)add:(VideoItem*)item cancelBlock:(void(^)(BOOL cancel))block {
    __weak typeof(self) wself = self;
    
    void(^executeBlock)() = ^{
        DownloadItem* downloadItem = [[DownloadItem alloc] initWithVideoItem:item];
        [wself.items addObject:downloadItem];
        [downloadItem action:wself.downloader];
        block(NO);
    };
    
    if (self.monitor.currentNetowrk == NetworkTypeWWAN) {
        [self showNetworkAlertVC:^(BOOL cancel) {
            if (cancel) {
                block(YES);
            } else {
                executeBlock();
            }

        }];
    } else {
        executeBlock();
    }
}

- (void)action:(NSUInteger)index cancelBlock:(void(^)(BOOL download))block {
    DownloadItem* item = self.items[index];
    
    __weak typeof(self) wself = self;
    void(^executeBlock)() = ^{
        [item action:wself.downloader];
        block(NO);
    };
    
    if (self.monitor.currentNetowrk == NetworkTypeWWAN
        && (item.state == DownloadStateSuspend || item.state == DownloadStateNone)) {
        [self showNetworkAlertVC:^(BOOL cancel) {
            if (cancel) {
                block(YES);
            } else {
                executeBlock();
            }
        }];
    } else {
        executeBlock();
    }
}

- (void)stop:(NSUInteger)index {
    DownloadItem* item = self.items[index];
    [item stop:self.downloader];
}

- (void)remove:(NSUInteger)index {
    DownloadItem* item = self.items[index];
    [item remove:self.downloader];
    [self.items removeObjectAtIndex:index];
}

#pragma mark - BDCloudMediaDownloadDelegate

- (void)taskStart:(BDCloudMediaDownloadTask*)task {
}

- (void)task:(BDCloudMediaDownloadTask*)task needAuthentication:(NSMutableDictionary*)parameters {
    for (DownloadItem* item in self.items) {
        if (item.task == task) {
            if (item.info.token.length != 0) {
                [parameters setObject:item.info.token forKey:@"token"];
            }
            break;
        }
    }
}

- (void)task:(BDCloudMediaDownloadTask*)task progress:(float)progress {
    NSUInteger index = 0;
    for (DownloadItem* item in self.items) {
        if (item.task == task) {
            if (self.updateBlock) {
                self.updateBlock(index);
            }
            break;
        }
        ++index;
    }
}

- (void)taskEnd:(BDCloudMediaDownloadTask*)task error:(NSError*)error {
    NSUInteger index = 0;
    for (DownloadItem* item in self.items) {
        if (item.task == task) {
            if (error) {
                if (task.state == BDCloudMediaDownloadTaskStateSuspend) {
                    item.state = DownloadStateSuspend;
                } else {
                    item.state = DownloadStateNone;
                }
            } else {
                item.state = DownloadStateCompleted;
            }
            if (self.updateBlock) {
                self.updateBlock(index);
            }
            break;
        }
        ++index;
    }
}

#pragma mark - 
- (void)downloadVideo:(NSString*)url cancelBlock:(void (^)(BOOL))block {
}

- (VideoItem*)previousVideo:(NSString*)url {
    NSInteger index = 0;
    for (DownloadItem* item in self.items) {
        NSString* offlineURL = [item.item.path stringByAppendingPathComponent:item.item.index];
        if ([offlineURL isEqualToString:url] || [item.info.url isEqualToString:url]) {
            if (--index >= 0) {
                DownloadItem* previous = self.items[index];
                if (previous.state == DownloadStateCompleted) {
                    VideoItem* previousVideo = [[VideoItem alloc] init];
                    previousVideo.title = previous.info.title;
                    previousVideo.detail = previous.info.detail;
                    previousVideo.img = previous.info.img;
                    
                    NSString* playURL = [previous.item.path stringByAppendingPathComponent:previous.item.index];
                    previousVideo.url = playURL;
                    return previousVideo;
                } else {
                    return previous.info;
                }
            }
            return nil;
        }
        
        ++index;
    }
    return nil;
}

- (VideoItem*)nextVideo:(NSString*)url {
    NSInteger index = 0;
    for (DownloadItem* item in self.items) {
        NSString* offlineURL = [item.item.path stringByAppendingPathComponent:item.item.index];
        if ([offlineURL isEqualToString:url] || [item.info.url isEqualToString:url]) {
            if (++index < self.items.count) {
                DownloadItem* previous = self.items[index];
                if (previous.state == DownloadStateCompleted) {
                    VideoItem* previousVideo = [[VideoItem alloc] init];
                    previousVideo.title = previous.info.title;
                    previousVideo.detail = previous.info.detail;
                    previousVideo.img = previous.info.img;
                    
                    NSString* playURL = [previous.item.path stringByAppendingPathComponent:previous.item.index];
                    previousVideo.url = playURL;
                    return previousVideo;
                } else {
                    return previous.info;
                }
            }
            return nil;
        }
        
        ++index;
    }
    return nil;
}

- (BOOL)downloadable:(NSString*)url {
    return [self isDownloading:url];
}

- (void)networkChanged:(NetworkType)network {
    if (network == NetworkTypeWWAN) {
        BOOL hasDownladingTask = NO;
        for (DownloadItem* item in self.items) {
            if (item.state == DownloadStateRunning) {
                hasDownladingTask = YES;
                break;
            }
        }
        
        if (hasDownladingTask) {
            __weak typeof(self) wself = self;
            [self showNetworkAlertVC:^(BOOL cancel) {
                if (cancel) {
                    [wself cancenDownloads];
                }
            }];
        }
    } else if (network == NetworkTypeWIFI) {
        [self continueDownloads];
    }
}

- (void)showNetworkAlertVC:(void(^)(BOOL cancel))block {
    UINavigationController* nv = (UINavigationController*)[UIApplication sharedApplication].keyWindow.rootViewController;
    UIStoryboard* mainBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    
    NetworkAlertVC* vc = (NetworkAlertVC*)[mainBoard instantiateViewControllerWithIdentifier:@"NetworkAlertVC"];
    vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    vc.cancelBlock = ^(BOOL cancel){
        block(cancel);
        [nv.topViewController dismissViewControllerAnimated:YES completion:nil];
    };
    
    [nv.topViewController presentViewController:vc animated:YES completion:nil];
}

@end
